package DatabaseManager;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public abstract class Table {
	
	/**
	 * Constructs a new table (not actually on disk yet).
	 * @param db_mgr - DBManager for this table
	 * @throws SQLException
	 * @throws ClassNotFoundException
	 */
	public Table(DBManager db_mgr) throws SQLException, ClassNotFoundException {
		this.db_mgr = db_mgr;
	}

	/**
	 * Finishes the process of dumping data from file.
	 * @throws SQLException
	 */
	public void finalizeInsertTable() throws SQLException {
		db_mgr.finalizeBatchInsert();
	}

	/**
	 * Inserts values during dumping data (actually batches them)
	 * @param values
	 * @throws SQLException
	 */
	public void InsertTable(String[] values) throws SQLException {
		db_mgr.batchInsert(table_name, columns, values);
	}

	/**
	 * Inserts a single value to the table.
	 * @param values - values to be inserted
	 * @throws SQLException
	 */
	public void SimpleInsertTable(String[] values) throws SQLException {
		db_mgr.InsertTable(table_name, columns, values);
	}
	
	/**
	 * Inserts values to the table using a query.
	 * @param query - query whose output we insert.
	 * @param attributes - attributes where we insert values
	 * @throws SQLException
	 */
	public void InsertTableUsingQuery(String query, String[] attributes) throws SQLException {
		db_mgr.InsertTableUsingQuery(table_name, query, attributes);
	}

	/**
	 * Clears the table.
	 * @throws SQLException
	 */
	public void ClearTable() throws SQLException {
		db_mgr.ClearTable(table_name);
	}

	/**
	 * Deletes rows from the table.
	 * @param where - what should we delete.
	 * @throws SQLException
	 */
	public void DeleteFrom(String where) throws SQLException {
		db_mgr.DeleteFromTable(table_name, where);
	}
	
	/**
	 * Updates all columns but the primary key with values,
	 * in all rows in "where".
	 * @param values - values to assign to columns.
	 * @param where - which rows to update.
	 * @throws SQLException 
	 */
	public void UpdateAll(String[] values, String where) throws SQLException {
		
		List<String> cols = new ArrayList<String>();
		for (String column : columns)
			if (!column.equals(primaryKey))
				cols.add(column);
		
		String[] cols1 = new String[cols.size()];
		for (int i=0; i<cols1.length; i++)
			cols1[i] = cols.get(i);
		
		db_mgr.UpdateTable(table_name, cols1, values, where);
	}

	/**
	 * Creates the table (in the database, but without any data).
	 * @throws SQLException
	 */
	public void CreateTable() throws SQLException {
		// default key name
		db_mgr.CreateTable(table_name, columns, primaryKey, foreignKey,
				dataTypes, isDataTypeNull, isMyISAM);
	}

	/**
	 * Drops the table.
	 * @throws SQLException
	 */
	public void DropTable() throws SQLException {
		try {
			db_mgr.DeleteTable(table_name);
		} catch (SQLException e) {
			// if table is not exists just return
			if (e.getErrorCode() == 1051)
				return;

			throw e;
		}
	}
	
	/**
	 * Creates an index on the table
	 * @param column - column to put index on 
	 * @param type - type of index (hash, btree...)
	 * @param indexName - name of index
	 * @throws SQLException
	 */
	public void CreateIndex(String column, String type, String indexName) throws SQLException {
		db_mgr.CreateIndex(table_name, column, type, indexName);
	}
	
	/**
	 * Changes the table's engine to InnoDB
	 * @throws SQLException
	 */
	public void toInnoDB() throws SQLException {
		db_mgr.changeTableToInnoDB(table_name);
	}
	
	/**
	 * Adds a foreign key constraint to the table
	 * @param constraintName - name of the constraint
	 * @param column - column that is a foreign key
	 * @param references - format: table(column) that the foreign key references
	 * @throws SQLException
	 */
	public void addForeignKeyConstraint(String constraintName, String column, String references) throws SQLException {
		db_mgr.addForeignKeyConstraint(table_name, constraintName, column, references);
	}
	
	/**
	 * Adds a unique constraint to a column
	 * @param column's name
	 * @throws SQLException
	 */
	public void addUniqueConstraint(String column) throws SQLException {
		db_mgr.addUniqueConstraint(table_name, column);
	}

	/**
	 * Returns a result set with all rows in a certain page 
	 * @param pageNumber - number of page
	 * @param entriesPerPage - number of rows per page
	 * @param orderBy - attribute to order by
	 * @param select - what will the result set contain
	 * @param where 
	 * @return
	 * @throws SQLException
	 */
	protected ResultSet getPage(int pageNumber, int entriesPerPage,
			String orderBy, String select, String where, String otherTableName) throws SQLException {
		String query;
		query = "SELECT " + select;
		query += " FROM " + table_name + (otherTableName == null ? "" : ", " + otherTableName);
		if (where != null)
			query += " WHERE " + where;
		query += " ORDER BY " + orderBy;
		query += " LIMIT " + (pageNumber - 1) * entriesPerPage + ", "
				+ entriesPerPage;
		
		return db_mgr.QueryTable(query);
	}

	/**
	 * @return - table's name
	 */
	public String GetTableName() {
		return table_name;
	}

	/**
	 * @return - name of primary key
	 */
	public String GetPrimaryKey() {
		return primaryKey;
	}

	/**
	 * @return - names of all attributes
	 */
	public String[] GetColumnNames() {
		return columns;
	}

	// values relevant for the table
	protected DBManager db_mgr = null;
	protected String primaryKey;
	protected String table_name;
	protected String[] columns;
	protected String[] foreignKey; // null if not, else table_name(attribute)
	protected String[] dataTypes;
	protected boolean[] isDataTypeNull;
	protected boolean isMyISAM = false;
}